from flask import Flask, request, jsonify
from tensorflow.keras.applications import VGG16
from tensorflow.keras.applications.vgg16 import preprocess_input
from tensorflow.keras.preprocessing import image
from tensorflow.keras.models import Model
import numpy as np
import os

# 环境设置，用于避免某些 TensorFlow 的警告和错误
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 设置 TensorFlow 的日志级别
os.environ['KMP_DUPLICATE_LIB_OK'] = 'True'  # 环境变量用于解决 OpenMP 在 macOS 上的问题

# 加载预训练的 VGG16 模型，不包括最后的全连接层
base_model = VGG16(weights='imagenet', include_top=False)

# 定义新的模型，将原 VGG16 模型的输出直接作为新模型的输出
model = Model(inputs=base_model.input, outputs=base_model.output)

# 定义 Flask 应用
app = Flask(__name__)


# 定义函数 extract_features，用于从给定图片中提取特征
def extract_features(img_path, model):
    print("图片地址：", img_path)
    print("模型数据：", model)

    img = image.load_img(img_path, target_size=(224, 224))  # 加载图片并调整大小
    img_array = image.img_to_array(img)  # 将图片转换为 numpy 数组
    img_array = np.expand_dims(img_array, axis=0)  # 将数组形状改为 (1, height, width, channels)
    img_array = preprocess_input(img_array)  # 应用 VGG16 的预处理
    features = model.predict(img_array)  # 用模型提取特征
    flatten_features = features.flatten()  # # 扁平化特征使其成为一维数组
    # 归一化特征向量以比较它们的相似性, np.linalg.norm函数计算向量的模长，即欧氏距离。将flatten_features除以其模长即可得到单位向量。
    normalized_features = flatten_features / np.linalg.norm(flatten_features)
    return normalized_features  # 返回特征


# 定义函数 calculate_similarity，用于计算两个特征之间的相似度
def calculate_similarity(features1, features2):
    similarity = np.dot(features1, features2)  # 计算两个特征的点积
    return similarity  # 返回相似度


# 定义 Flask 路由，用于计算两个图片的相似度
# 它告诉 Flask，当 HTTP 请求的 URL 路径为 '/calculate_similarity' 且请求方法为 'POST' 时，应执行其下方的函数
@app.route('/calculate_similarity', methods=['POST'])
def calculate_similarity_endpoint():
    data = request.get_json()  # 获取请求中的 JSON 数据
    img_path1 = data['image_path1']  # 获取第一张图片的路径
    img_path2 = data['image_path2']  # 获取第二张图片的路径
    features1 = extract_features(img_path1, model)  # 提取第一张图片的特征
    features2 = extract_features(img_path2, model)  # 提取第二张图片的特征
    similarity = calculate_similarity(features1, features2)  # 计算两个特征的相似度
    return jsonify({"Similarity": similarity.item()})  # 返回 JSON 格式的相似度，使用 item() 将 numpy.float32 转换为 float


# 当脚本被直接运行时，启动 Flask 服务
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000, debug=True)  # 在 0.0.0.0:5000 上运行，打开 debug 模式
